package com.ccteam.fluidmusic.fluidmusic.common

import android.content.ComponentName
import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.os.CountDownTimer
import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaControllerCompat
import android.support.v4.media.session.PlaybackStateCompat
import com.ccteam.fluidmusic.fluidmusic.core.SettingCore
import com.ccteam.fluidmusic.fluidmusic.media.FluidMusicService
import com.ccteam.fluidmusic.fluidmusic.media.extensions.*
import com.ccteam.fluidmusic.fluidmusic.media.library.BrowseTree
import com.orhanobut.logger.Logger
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject
import javax.inject.Singleton

/**
 *
 * @author Xiaoc
 * @since 2020/3/5
 *
 * 该类为单例类，用来管理与 [androidx.media.MediaBrowserServiceCompat] 间的连接，而它的具体服务类
 * 就是 [com.ccteam.fluidmusic.fluidmusic.media.FluidMusicService]
 *
 * 该类存储着基本的可能跨Activity的信息（单例类，由Hilt管理）
 * 如 当前播放的歌曲信息、当前播放状态、与Service的连接状态等等，随时监听着Media的变化
 * 其中所有内容都使用热流 [MutableStateFlow] 或 [MutableSharedFlow] 进行存储，外部对其进行各种操作及观察收集操作
 *
 * 同时，该类还存在一些基本方法去订阅或者使用一些对媒体的操作
 */
@Singleton
class MusicServiceConnectionFlow @Inject constructor(
    private val settingCore: SettingCore,
    @ApplicationContext private val context: Context,
    private val browseTree: BrowseTree
){
    private val serviceComponent = ComponentName(context, FluidMusicService::class.java)

    /**
     * 是否与 [FluidMusicService] 连接成功，连接成功为true
     */
    private val _isConnected = MutableStateFlow(false)
    val isConnected get() = _isConnected.asStateFlow()

    /**
     * 本地音乐根目录ID（当 [isConnected] 为 true 时才能获取到
     */
    val localRootId : String get() = mediaBrowser.root

    /**
     * 正在播放的内容
     */
    private val _nowPlaying = MutableStateFlow(METADATA_NOTHING_PLAYING)
    val nowPlaying get() = _nowPlaying.asStateFlow()

    /**
     * 正在播放的状态
     */
    private val _nowPlaybackState = MutableStateFlow(EMPTY_PLAYBACK_STATE)
    val nowPlaybackState get() = _nowPlaybackState.asStateFlow()

    /**
     * 当前播放模式
     */
    private val _nowRepeatMode = MutableStateFlow(PlaybackStateCompat.REPEAT_MODE_NONE)
    val nowRepeatMode get() = _nowRepeatMode.asStateFlow()

    /**
     * 当前随机模式
     */
    private val _nowShuffleMode = MutableStateFlow(PlaybackStateCompat.SHUFFLE_MODE_NONE)
    val nowShuffleMode get() = _nowShuffleMode.asStateFlow()

    /**
     * 当前播放列表内容
     */
    private val _nowPlaylistQueue = MutableSharedFlow<List<MediaMetadataCompat>>(replay = 1,
        onBufferOverflow = BufferOverflow.DROP_OLDEST)
    val nowPlaylistQueue get() = _nowPlaylistQueue.asSharedFlow()

    /**
     * 当前控制器对象
     */
    private lateinit var _mediaController: MediaControllerCompat

    private val playlistCallback = PlaylistCallback()

    private val mediaBrowserConnectionCallback = MediaBrowserConnectionCallback(context)
    private val mediaBrowser = MediaBrowserCompat(
        context, serviceComponent,mediaBrowserConnectionCallback,null
    ).apply {
        connect()
    }

    private var countDownTimer: CountDownTimer? = null

    private val mediaControllerCallback = MediaControllerCallback()

    /**
     * 得到媒体控制器
     * 如果为未连接则为null
     */
    fun getMediaController(): MediaControllerCompat?{
        return if(_isConnected.value){
            _mediaController
        } else {
            null
        }
    }

    fun subscribe(parentId: String, callback: MediaBrowserCompat.SubscriptionCallback,bundle: Bundle) {
        mediaBrowser.subscribe(parentId, bundle, callback)
    }

    fun subscribe(parentId: String, callback: MediaBrowserCompat.SubscriptionCallback) {
        mediaBrowser.subscribe(parentId, callback)
    }

    fun unsubscribe(parentId: String, callback: MediaBrowserCompat.SubscriptionCallback) {
        mediaBrowser.unsubscribe(parentId, callback)
    }

    fun addOnlineMusicItems(parentId: String,items: List<MediaMetadataCompat>){
        browseTree.addOnlineMediaItems(parentId,items)
    }

    fun addOnlineMusicItem(parentId: String,item: MediaMetadataCompat){
        browseTree.addOnlineMediaItem(parentId,item)
    }
    /**
     * 定时音乐关闭任务
     */
    fun timerClose(enableTimer: Boolean,value: Int = 15){
        countDownTimer?.cancel()
        if(enableTimer){
            countDownTimer = object: CountDownTimer(value * 60L * 1000,value * 60L * 1000){
                override fun onTick(millisUntilFinished: Long) {}

                override fun onFinish() {
                    // 结束后关闭
                    settingCore.clearMusicTimer()
                    _mediaController.transportControls.pause()
                }

            }
            countDownTimer?.start()
        }
    }

    private inner class MediaBrowserConnectionCallback(private val context: Context):
        MediaBrowserCompat.ConnectionCallback(){

        override fun onConnected() {
            _mediaController = MediaControllerCompat(context,mediaBrowser.sessionToken).apply {
                registerCallback(mediaControllerCallback)
            }

            PlaylistManager.setPlaylistCallback(playlistCallback)
            _isConnected.value = true
        }

        override fun onConnectionSuspended() {
            _isConnected.tryEmit(false)
            PlaylistManager.clearPlaylistCallback()
        }

        override fun onConnectionFailed() {
            _isConnected.tryEmit(false)
            PlaylistManager.clearPlaylistCallback()
        }
    }

    private inner class MediaControllerCallback: MediaControllerCompat.Callback(){

        override fun onPlaybackStateChanged(state: PlaybackStateCompat?) {
            state?.let {
                _nowPlaybackState.tryEmit(it)
            }
        }

        override fun onMetadataChanged(metadata: MediaMetadataCompat?) {
            metadata?.let {
                _nowPlaying.tryEmit(
                    if(it.id == null){
                        METADATA_NOTHING_PLAYING
                    } else {
                        metadata
                    }
                )
                // 当播放内容改变后，再次提交一次播放列表更改通知播放列表改变播放高亮项
                _nowPlaylistQueue.tryEmit(PlaylistManager.getItems())
            }
        }

        override fun onShuffleModeChanged(shuffleMode: Int) {
            _nowShuffleMode.tryEmit(shuffleMode)
        }

        override fun onRepeatModeChanged(repeatMode: Int) {
            _nowRepeatMode.tryEmit(repeatMode)
        }

        override fun onSessionDestroyed() {
            mediaBrowserConnectionCallback.onConnectionSuspended()
        }
    }

    private inner class PlaylistCallback: PlaylistManager.PlaylistCallback{

        override fun playlistQueueChanged(playlistQueue: List<MediaMetadataCompat>) {
            _nowPlaylistQueue.tryEmit(playlistQueue)
        }

    }
}

val METADATA_NOTHING_PLAYING: MediaMetadataCompat = MediaMetadataCompat.Builder().apply {
    id = ""
    title = "纵想音乐的乐趣"
    artist = "Fluid Music"
    album = "ccteam"
    duration = 1
    queueId = -1
}.build()

/**
 * 闲置时的播放状态
 */
val EMPTY_PLAYBACK_STATE: PlaybackStateCompat = PlaybackStateCompat.Builder()
    .setState(PlaybackStateCompat.STATE_NONE,0,0f).build()